{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Multi-round inference\n",
    "\n",
    "In the previous tutorials, we have inferred the posterior using **single-round inference**. In **single-round inference**, we draw parameters from the prior, simulate the corresponding data, and then train a neural network to obtain the posterior. However,  if one is interested in only one particular observation `x_o` sampling from the prior can be inefficient in the number of simulations because one is effectively learning a posterior estimate for all observations in the prior space. In this tutorial, we show how one can alleviate this issue by performing **multi-round inference** with `sbi`.  \n",
    "\n",
    "**Multi-round inference** also starts by drawing parameters from the prior, simulating them, and training a neural network to estimate the posterior distribution. Afterwards, however, it continues inference in multiple rounds, focusing on a particular observation `x_o`. In each new round of inference, it draws samples from the obtained posterior distribution conditioned at `x_o` (instead of from the prior), simulates these, and trains the network again. This process can be repeated arbitrarily often to get increasingly good approximations to the true posterior distribution at `x_o`.\n",
    "\n",
    "Running multi-round inference can be more efficient in the number of simulations, but it will lead to the posterior no longer being amortized (i.e. it will be accurate only for a specific observation `x_o`, not for any `x`)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note, you can find the original version of this notebook at [https://github.com/sbi-dev/sbi/blob/main/tutorials/03_multiround_inference.ipynb](https://github.com/sbi-dev/sbi/blob/main/tutorials/03_multiround_inference.ipynb) in the `sbi` repository."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Main syntax"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 2 rounds: first round simulates from the prior, second round simulates parameter set\n",
    "# that were sampled from the obtained posterior.\n",
    "num_rounds = 2\n",
    "# The specific observation we want to focus the inference on.\n",
    "x_o = torch.zeros(3,)\n",
    "\n",
    "inference = SNPE(prior)\n",
    "\n",
    "posteriors = []\n",
    "proposal = prior\n",
    "\n",
    "for _ in range(num_rounds):\n",
    "    theta, x = simulate_for_sbi(simulator, proposal, num_simulations=500)\n",
    "\n",
    "    # In `SNLE` and `SNRE`, you should not pass the `proposal` to `.append_simulations()`\n",
    "    density_estimator = inference.append_simulations(\n",
    "        theta, x, proposal=proposal\n",
    "    ).train()\n",
    "    posterior = inference.build_posterior(density_estimator)\n",
    "    posteriors.append(posterior)\n",
    "    proposal = posterior.set_default_x(x_o)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Linear Gaussian example\n",
    "Below, we give a full example of inferring the posterior distribution over multiple rounds."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "\n",
    "from sbi.inference import SNPE, prepare_for_sbi, simulate_for_sbi\n",
    "from sbi.utils.get_nn_models import posterior_nn\n",
    "from sbi import utils as utils\n",
    "from sbi import analysis as analysis\n",
    "\n",
    "_ = torch.manual_seed(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we define a simple prior and simulator and ensure that they comply with `sbi` by using `prepare_for_sbi`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_dim = 3\n",
    "prior = utils.BoxUniform(low=-2 * torch.ones(num_dim), high=2 * torch.ones(num_dim))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def linear_gaussian(theta):\n",
    "    return theta + 1.0 + torch.randn_like(theta) * 0.1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "simulator, prior = prepare_for_sbi(linear_gaussian, prior)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, we instantiate the inference object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "inference = SNPE(prior=prior)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And we can run inference. In this example, we will run inference over `2` rounds, potentially leading to a more focused posterior around the observation `x_o`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "68f10e6e42ca4b50af913d30a40bfdef",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Running 500 simulations.:   0%|          | 0/500 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " Neural network successfully converged after 157 epochs."
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "36530955ad034757a7ffb956240c9713",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Drawing 500 posterior samples:   0%|          | 0/500 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "3c159618df4c44c6911da5f612498f51",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Running 500 simulations.:   0%|          | 0/500 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using SNPE-C with atomic loss\n",
      " Neural network successfully converged after 58 epochs."
     ]
    }
   ],
   "source": [
    "num_rounds = 2\n",
    "x_o = torch.zeros(\n",
    "    3,\n",
    ")\n",
    "\n",
    "posteriors = []\n",
    "proposal = prior\n",
    "\n",
    "for _ in range(num_rounds):\n",
    "    theta, x = simulate_for_sbi(simulator, proposal, num_simulations=500)\n",
    "    density_estimator = inference.append_simulations(\n",
    "        theta, x, proposal=proposal\n",
    "    ).train()\n",
    "    posterior = inference.build_posterior(density_estimator)\n",
    "    posteriors.append(posterior)\n",
    "    proposal = posterior.set_default_x(x_o)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " Note that, for `num_rounds>1`, the posterior is no longer amortized: it will give good results when sampled around `x=observation`, but possibly bad results for other `x`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once we have obtained the posterior, we can `.sample()`, `.log_prob()`, or `.pairplot()` in the same way as for the simple interface."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1d3b3e5bbc5c4521a42137767412c25d",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Drawing 10000 posterior samples:   0%|          | 0/10000 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 360x360 with 9 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "posterior_samples = posterior.sample((10000,), x=x_o)\n",
    "\n",
    "# plot posterior samples\n",
    "_ = analysis.pairplot(\n",
    "    posterior_samples, limits=[[-2, 2], [-2, 2], [-2, 2]], figsize=(5, 5)\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
